﻿namespace Holoville.HOTween
{
    using Holoville.HOTween.Core;
    using Holoville.HOTween.Plugins;
    using Holoville.HOTween.Plugins.Core;
    using System;
    using System.Collections.Generic;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEngine;

    public class Tweener : ABSTweenComponent
    {
        internal float _delay;
        internal AnimationCurve _easeAnimationCurve;
        internal float _easeOvershootOrAmplitude = Holoville.HOTween.HOTween.defEaseOvershootOrAmplitude;
        internal float _easePeriod = Holoville.HOTween.HOTween.defEasePeriod;
        internal EaseType _easeType = Holoville.HOTween.HOTween.defEaseType;
        private float _elapsedDelay;
        private EaseType _originalEaseType;
        internal bool _pixelPerfect;
        internal bool _speedBased;
        private object _target;
        internal float delayCount;
        private bool isPartialled;
        internal TweenDelegate.TweenCallback onPluginOverwritten;
        internal object[] onPluginOverwrittenParms;
        internal TweenDelegate.TweenCallbackWParms onPluginOverwrittenWParms;
        internal List<ABSTweenPlugin> plugins;
        private PlugVector3Path pv3Path;

        internal Tweener(object p_target, float p_duration, TweenParms p_parms)
        {
            this._target = p_target;
            base._duration = p_duration;
            p_parms.InitializeObject(this, this._target);
            if ((this.plugins != null) && (this.plugins.Count > 0))
            {
                base._isEmpty = false;
            }
            base.SetFullDuration();
        }

        protected override void ApplyCallback(bool p_wParms, CallbackType p_callbackType, TweenDelegate.TweenCallback p_callback, TweenDelegate.TweenCallbackWParms p_callbackWParms, params object[] p_callbackParms)
        {
            if (p_callbackType == CallbackType.OnPluginOverwritten)
            {
                this.onPluginOverwritten = p_callback;
                this.onPluginOverwrittenWParms = p_callbackWParms;
                this.onPluginOverwrittenParms = p_callbackParms;
            }
            else
            {
                base.ApplyCallback(p_wParms, p_callbackType, p_callback, p_callbackWParms, p_callbackParms);
            }
        }

        internal override void Complete(bool p_autoRemoveFromHOTween)
        {
            if (base._enabled && (base._loops >= 0))
            {
                base._fullElapsed = !float.IsPositiveInfinity(base._fullDuration) ? base._fullDuration : base._duration;
                base.Update(0f, true);
                if (base._autoKillOnComplete)
                {
                    this.Kill(p_autoRemoveFromHOTween);
                }
            }
        }

        private static int ConvertWaypointIdToPathId(PlugVector3Path p_plugVector3Path, int p_waypointId, bool p_isStartingWp)
        {
            if (p_waypointId == -1)
            {
                return (!p_isStartingWp ? (p_plugVector3Path.path.path.Length - 2) : 1);
            }
            if (p_plugVector3Path.hasAdditionalStartingP)
            {
                return (p_waypointId + 2);
            }
            return (p_waypointId + 1);
        }

        internal override void FillPluginsList(List<ABSTweenPlugin> p_plugs)
        {
            if (this.plugins != null)
            {
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    p_plugs.Add(this.plugins[i]);
                }
            }
        }

        internal void ForceSetSpeedBasedDuration()
        {
            if (this._speedBased && (this.plugins != null))
            {
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    this.plugins[i].ForceSetSpeedBasedDuration();
                }
                base._duration = 0f;
                for (int j = 0; j < count; j++)
                {
                    ABSTweenPlugin plugin = this.plugins[j];
                    if (plugin.duration > base._duration)
                    {
                        base._duration = plugin.duration;
                    }
                }
                base.SetFullDuration();
            }
        }

        private PlugVector3Path GetPlugVector3PathPlugin()
        {
            if (this.plugins != null)
            {
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    ABSTweenPlugin plugin = this.plugins[i];
                    PlugVector3Path path = plugin as PlugVector3Path;
                    if (path != null)
                    {
                        return path;
                    }
                }
            }
            return null;
        }

        public Vector3 GetPointOnPath(float t)
        {
            PlugVector3Path path = this.GetPlugVector3PathPlugin();
            if (path == null)
            {
                return Vector3.zero;
            }
            this.Startup();
            return path.GetConstPointOnPath(t);
        }

        internal override List<IHOTweenComponent> GetTweensById(string p_id)
        {
            List<IHOTweenComponent> list = new List<IHOTweenComponent>();
            if (this.id == p_id)
            {
                list.Add(this);
            }
            return list;
        }

        internal override List<IHOTweenComponent> GetTweensByIntId(int p_intId)
        {
            List<IHOTweenComponent> list = new List<IHOTweenComponent>();
            if (this.intId == p_intId)
            {
                list.Add(this);
            }
            return list;
        }

        public override List<object> GetTweenTargets()
        {
            return new List<object> { this.target };
        }

        protected override bool GoTo(float p_time, bool p_play, bool p_forceUpdate, bool p_ignoreCallbacks)
        {
            if (!base._enabled)
            {
                return false;
            }
            if (p_time > base._fullDuration)
            {
                p_time = base._fullDuration;
            }
            else if (p_time < 0f)
            {
                p_time = 0f;
            }
            if (!p_forceUpdate && (base._fullElapsed == p_time))
            {
                if (!base._isComplete && p_play)
                {
                    this.Play();
                }
                return base._isComplete;
            }
            base._fullElapsed = p_time;
            this.delayCount = 0f;
            this._elapsedDelay = this._delay;
            this.Update(0f, true, false, p_ignoreCallbacks, false);
            if (!base._isComplete && p_play)
            {
                this.Play();
            }
            return base._isComplete;
        }

        public override bool IsLinkedTo(object p_target)
        {
            return (p_target == this._target);
        }

        public override bool IsTweening(int p_id)
        {
            if (!base._enabled)
            {
                return false;
            }
            return ((this.intId == p_id) && !base._isPaused);
        }

        public override bool IsTweening(object p_target)
        {
            if (!base._enabled)
            {
                return false;
            }
            return ((p_target == this._target) && !base._isPaused);
        }

        public override bool IsTweening(string p_id)
        {
            if (!base._enabled)
            {
                return false;
            }
            return ((this.id == p_id) && !base._isPaused);
        }

        internal override void Kill(bool p_autoRemoveFromHOTween)
        {
            if (!base._destroyed)
            {
                if (Holoville.HOTween.HOTween.overwriteManager != null)
                {
                    Holoville.HOTween.HOTween.overwriteManager.RemoveTween(this);
                }
                this.plugins = null;
                base.Kill(p_autoRemoveFromHOTween);
            }
        }

        protected override void OnPlay()
        {
            if ((this._delay > 0f) && (this._elapsedDelay <= 0f))
            {
                this.Update(0f, true, true, false, true);
            }
        }

        protected override void OnStart()
        {
            if (!this.steadyIgnoreCallbacks && !base.ignoreCallbacks)
            {
                if (Holoville.HOTween.HOTween.overwriteManager != null)
                {
                    Holoville.HOTween.HOTween.overwriteManager.AddTween(this);
                }
                base.OnStart();
            }
        }

        public void Play(bool p_skipDelay)
        {
            if (base._enabled)
            {
                if (p_skipDelay)
                {
                    this.SkipDelay();
                }
                this.Play();
            }
        }

        public void PlayForward(bool p_skipDelay)
        {
            if (base._enabled)
            {
                if (p_skipDelay)
                {
                    this.SkipDelay();
                }
                this.PlayForward();
            }
        }

        protected override void Reset()
        {
            base.Reset();
            this.isFrom = false;
            this.plugins = null;
            this.isPartialled = false;
            this.pv3Path = null;
            this._delay = this._elapsedDelay = this.delayCount = 0f;
            this._pixelPerfect = false;
            this._speedBased = false;
            this._easeType = Holoville.HOTween.HOTween.defEaseType;
            this._easeOvershootOrAmplitude = Holoville.HOTween.HOTween.defEaseOvershootOrAmplitude;
            this._easePeriod = Holoville.HOTween.HOTween.defEasePeriod;
            this._originalEaseType = Holoville.HOTween.HOTween.defEaseType;
            this.onPluginOverwritten = null;
            base.onStepCompleteWParms = null;
            this.onPluginOverwrittenParms = null;
        }

        public void ResetAndChangeParms(TweenType p_tweenType, float p_newDuration, TweenParms p_newParms)
        {
            if (base._destroyed)
            {
                TweenWarning.Log("ResetAndChangeParms can't run because the tween was destroyed - set AutoKill or autoKillOnComplete to FALSE if you want to avoid destroying a tween after completion");
            }
            else
            {
                this.Reset();
                base._duration = p_newDuration;
                if (p_tweenType == TweenType.From)
                {
                    p_newParms = p_newParms.IsFrom();
                }
                p_newParms.InitializeObject(this, this._target);
                if ((this.plugins != null) && (this.plugins.Count > 0))
                {
                    base._isEmpty = false;
                }
                base.SetFullDuration();
            }
        }

        public void ResetPath()
        {
            this.isPartialled = false;
            base._duration = !this.speedBased ? base._originalDuration : base._originalNonSpeedBasedDuration;
            this._easeType = this._originalEaseType;
            this.pv3Path.ResetToFullPath(base._duration, this._easeType);
            this.Startup(true);
            if (!base._isPaused)
            {
                this.Restart(true);
            }
            else
            {
                this.Rewind(true);
            }
        }

        public override void Restart()
        {
            this.Restart(false);
        }

        public void Restart(bool p_skipDelay)
        {
            if (base._fullElapsed == 0f)
            {
                this.PlayForward(p_skipDelay);
            }
            else
            {
                this.Rewind(true, p_skipDelay);
            }
        }

        public override void Rewind()
        {
            this.Rewind(false);
        }

        public void Rewind(bool p_skipDelay)
        {
            this.Rewind(false, p_skipDelay);
        }

        private void Rewind(bool p_play, bool p_skipDelay)
        {
            if (base._enabled)
            {
                this.Startup();
                if (!base._hasStarted)
                {
                    this.OnStart();
                }
                base._isComplete = false;
                base._isLoopingBack = false;
                this.delayCount = !p_skipDelay ? this._delay : 0f;
                this._elapsedDelay = !p_skipDelay ? 0f : this._delay;
                base._completedLoops = 0;
                base._fullElapsed = base._elapsed = 0f;
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    ABSTweenPlugin plugin = this.plugins[i];
                    if (plugin.easeReversed)
                    {
                        plugin.ReverseEase();
                    }
                    plugin.Rewind();
                }
                if (base._fullElapsed != base.prevFullElapsed)
                {
                    base.OnUpdate();
                    if (base._fullElapsed == 0f)
                    {
                        base.OnRewinded();
                    }
                }
                base.prevFullElapsed = base._fullElapsed;
                if (p_play)
                {
                    this.Play();
                }
                else
                {
                    this.Pause();
                }
            }
        }

        internal override void SetIncremental(int p_diffIncr)
        {
            if (this.plugins != null)
            {
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    this.plugins[i].ForceSetIncremental(p_diffIncr);
                }
            }
        }

        private void SkipDelay()
        {
            if (this.delayCount > 0f)
            {
                this.delayCount = 0f;
                this._elapsedDelay = this._delay;
                base._elapsed = base._fullElapsed = 0f;
            }
        }

        protected override void Startup()
        {
            this.Startup(false);
        }

        private void Startup(bool p_force)
        {
            if (p_force || !base.startupDone)
            {
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    ABSTweenPlugin plugin = this.plugins[i];
                    if (!plugin.wasStarted)
                    {
                        plugin.Startup();
                    }
                }
                if (this._speedBased)
                {
                    base._originalNonSpeedBasedDuration = base._duration;
                    base._duration = 0f;
                    for (int j = 0; j < count; j++)
                    {
                        ABSTweenPlugin plugin2 = this.plugins[j];
                        if (plugin2.duration > base._duration)
                        {
                            base._duration = plugin2.duration;
                        }
                    }
                    base.SetFullDuration();
                }
                else if (p_force)
                {
                    base.SetFullDuration();
                }
                base.Startup();
            }
        }

        internal override bool Update(float p_shortElapsed, bool p_forceUpdate, bool p_isStartupIteration, bool p_ignoreCallbacks)
        {
            return this.Update(p_shortElapsed, p_forceUpdate, p_isStartupIteration, p_ignoreCallbacks, false);
        }

        internal bool Update(float p_shortElapsed, bool p_forceUpdate, bool p_isStartupIteration, bool p_ignoreCallbacks, bool p_ignoreDelay = false)
        {
            if (base._destroyed)
            {
                return true;
            }
            if ((this._target == null) || this._target.Equals(null))
            {
                this.Kill(false);
                return true;
            }
            if (!base._enabled)
            {
                return false;
            }
            if ((base._isComplete && !base._isReversed) && !p_forceUpdate)
            {
                return true;
            }
            if (((base._fullElapsed == 0f) && base._isReversed) && !p_forceUpdate)
            {
                return false;
            }
            if (base._isPaused && !p_forceUpdate)
            {
                return false;
            }
            base.ignoreCallbacks = p_isStartupIteration || p_ignoreCallbacks;
            if (p_ignoreDelay || (this.delayCount == 0f))
            {
                this.Startup();
                if (!base._hasStarted)
                {
                    this.OnStart();
                }
                if (!base._isReversed)
                {
                    base._fullElapsed += p_shortElapsed;
                    base._elapsed += p_shortElapsed;
                }
                else
                {
                    base._fullElapsed -= p_shortElapsed;
                    base._elapsed -= p_shortElapsed;
                }
                if (base._fullElapsed > base._fullDuration)
                {
                    base._fullElapsed = base._fullDuration;
                }
                else if (base._fullElapsed < 0f)
                {
                    base._fullElapsed = 0f;
                }
            }
            else
            {
                if (base._timeScale != 0f)
                {
                    this._elapsedDelay += p_shortElapsed / base._timeScale;
                }
                if (this._elapsedDelay < this.delayCount)
                {
                    return false;
                }
                if (base._isReversed)
                {
                    base._fullElapsed = base._elapsed = 0f;
                }
                else
                {
                    base._fullElapsed = base._elapsed = this._elapsedDelay - this.delayCount;
                    if (base._fullElapsed > base._fullDuration)
                    {
                        base._fullElapsed = base._fullDuration;
                    }
                }
                this._elapsedDelay = this.delayCount;
                this.delayCount = 0f;
                this.Startup();
                if (!base._hasStarted)
                {
                    this.OnStart();
                }
            }
            bool flag = base._isComplete;
            bool flag2 = (!base._isReversed && !flag) && (base._elapsed >= base._duration);
            base.SetLoops();
            base.SetElapsed();
            base._isComplete = (!base._isReversed && (base._loops >= 0)) && (base._completedLoops >= base._loops);
            bool flag3 = !flag && base._isComplete;
            float num = base._isLoopingBack ? (base._duration - base._elapsed) : base._elapsed;
            int count = this.plugins.Count;
            for (int i = 0; i < count; i++)
            {
                ABSTweenPlugin plugin = this.plugins[i];
                if ((!base._isLoopingBack && plugin.easeReversed) || ((base._isLoopingBack && (base._loopType == LoopType.YoyoInverse)) && !plugin.easeReversed))
                {
                    plugin.ReverseEase();
                }
                if (base._duration > 0f)
                {
                    plugin.Update(num);
                    base.OnPluginUpdated(plugin);
                }
                else
                {
                    base.OnPluginUpdated(plugin);
                    plugin.Complete();
                    if (!flag)
                    {
                        flag3 = true;
                    }
                }
            }
            if (base._fullElapsed != base.prevFullElapsed)
            {
                base.OnUpdate();
                if (base._fullElapsed == 0f)
                {
                    if (!base._isPaused)
                    {
                        base._isPaused = true;
                        base.OnPause();
                    }
                    base.OnRewinded();
                }
            }
            if (flag3)
            {
                if (!base._isPaused)
                {
                    base._isPaused = true;
                    base.OnPause();
                }
                base.OnComplete();
            }
            else if (flag2)
            {
                base.OnStepComplete();
            }
            base.ignoreCallbacks = false;
            base.prevFullElapsed = base._fullElapsed;
            return flag3;
        }

        public Tweener UsePartialPath(int p_waypointId0, int p_waypointId1)
        {
            EaseType type = this.isPartialled ? this._originalEaseType : this._easeType;
            return this.UsePartialPath(p_waypointId0, p_waypointId1, -1f, type);
        }

        public Tweener UsePartialPath(int p_waypointId0, int p_waypointId1, EaseType p_newEaseType)
        {
            return this.UsePartialPath(p_waypointId0, p_waypointId1, -1f, p_newEaseType);
        }

        public Tweener UsePartialPath(int p_waypointId0, int p_waypointId1, float p_newDuration)
        {
            EaseType type = !this.isPartialled ? this._easeType : this._originalEaseType;
            return this.UsePartialPath(p_waypointId0, p_waypointId1, p_newDuration, type);
        }

        public Tweener UsePartialPath(int p_waypointId0, int p_waypointId1, float p_newDuration, EaseType p_newEaseType)
        {
            if (this.plugins.Count > 1)
            {
                TweenWarning.Log("Applying a partial path on a Tweener (" + this._target + ") with more than one plugin/property being tweened is not allowed");
                return this;
            }
            if (this.pv3Path == null)
            {
                this.pv3Path = this.GetPlugVector3PathPlugin();
                if (this.pv3Path == null)
                {
                    TweenWarning.Log("Tweener for " + this._target + " contains no PlugVector3Path plugin");
                    return this;
                }
            }
            this.Startup();
            if (!this.isPartialled)
            {
                this.isPartialled = true;
                base._originalDuration = base._duration;
                this._originalEaseType = this._easeType;
            }
            int num = ConvertWaypointIdToPathId(this.pv3Path, p_waypointId0, true);
            int num2 = ConvertWaypointIdToPathId(this.pv3Path, p_waypointId1, false);
            float waypointsLengthPercentage = this.pv3Path.GetWaypointsLengthPercentage(num, num2);
            float num4 = (num != 0) ? this.pv3Path.GetWaypointsLengthPercentage(0, num) : 0f;
            base._duration = (p_newDuration < 0f) ? (base._originalDuration * waypointsLengthPercentage) : p_newDuration;
            this._easeType = p_newEaseType;
            this.pv3Path.SwitchToPartialPath(base._duration, p_newEaseType, num4, waypointsLengthPercentage);
            this.Startup(true);
            if (!base._isPaused)
            {
                this.Restart(true);
            }
            else
            {
                this.Rewind(true, true);
            }
            return this;
        }

        public float delay
        {
            get
            {
                return this._delay;
            }
        }

        public AnimationCurve easeAnimationCurve
        {
            get
            {
                return this._easeAnimationCurve;
            }
            set
            {
                this._easeAnimationCurve = value;
                this._easeType = EaseType.AnimationCurve;
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    this.plugins[i].SetEase(this._easeType);
                }
            }
        }

        public float easeOvershootOrAmplitude
        {
            get
            {
                return this._easeOvershootOrAmplitude;
            }
            set
            {
                this._easeOvershootOrAmplitude = value;
            }
        }

        public float easePeriod
        {
            get
            {
                return this._easePeriod;
            }
            set
            {
                this._easePeriod = value;
            }
        }

        public EaseType easeType
        {
            get
            {
                return this._easeType;
            }
            set
            {
                this._easeType = value;
                int count = this.plugins.Count;
                for (int i = 0; i < count; i++)
                {
                    this.plugins[i].SetEase(this._easeType);
                }
            }
        }

        public float elapsedDelay
        {
            get
            {
                return this._elapsedDelay;
            }
        }

        public bool isFrom { get; internal set; }

        public bool pixelPerfect
        {
            get
            {
                return this._pixelPerfect;
            }
        }

        public bool speedBased
        {
            get
            {
                return this._speedBased;
            }
        }

        public object target
        {
            get
            {
                return this._target;
            }
        }
    }
}

